package com.gking.centerSystem.utils;

import com.gking.centerSystem.common.BaseContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

@Slf4j
@ServerEndpoint("/websocket/{userId}")
@Component
public class WebSocketServer {
    //在线数量
    private static Integer onlineCount = 0;

    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    private static final CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();

    // 用户id对应的websocket服务
    private static final Map<String, WebSocketServer> userSession = new HashMap<>();
    // websocket服务对应的用户id
    private static final Map<String, String> sessionUser = new HashMap<>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;

    //接收sid(一般是用户账号id）
    private String sid = "";


    /**
     * 连接建立成功调用的方法
     *
     * @param session 会话空间
     * @param userId  userId
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.sid = userId;

        webSocketSet.add(this);   //加入set中
        addOnlineCount();      //在线数加1

        userSession.put(userId, this);
        sessionUser.put(this.toString(), userId);

        log.info("webSocket this: {} ", this);
        log.info("webSocket 有新窗口开始监听:   , 当前在线人数为: {} ", getOnlineCount());
        log.info("webSocket 新窗口存在的账号：{}", webSocketSet.toString());

        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            System.out.println("websocket IO异常");
        }
    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this); //从set中删除
        userSession.remove(sessionUser.get(this.toString()));
        sessionUser.remove(this.toString());

        subOnlineCount();      //在线数减1
        log.info("webSocket 有一连接关闭！当前在线人数为：" + getOnlineCount());
        log.info("webSocket 有一连接关闭！webSocketSet：" + webSocketSet.toString());
        log.info("webSocket 有一连接关闭！userSession：" + userSession.toString());
        log.info("webSocket 有一连接关闭！sessionUser：" + sessionUser.toString());
    }


    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("webSocket 收到来自窗口 {}  的信息: {}", session, message);

        //群发消息
        for (WebSocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * @param session 会话
     * @param error   错误
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("webSocket 发生错误");
        error.printStackTrace();
    }


    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }


    /**
     * 群发自定义消息
     *
     * @param message 信息
     * @throws IOException 抛出的错误
     */
    public static void sendInfo(String message) throws IOException {
        log.info("webSocket 群发推送消息到窗口  ，推送内容:" + message);

        for (WebSocketServer item : webSocketSet) {
            log.info("item : {}", item);
            log.info("item.sid : {}", item.sid);
            try {
                item.sendMessage(message);
            } catch (IOException ignored) {
                continue;
            }
        }
    }


    /**
     * 推送消息给特定用户
     *
     * @param targetId 目标id
     * @param message  消息
     * @throws IOException 错误
     */
    public static void sendMessageTo(String targetId,   String message) throws IOException {
        log.info("webSocket 指定用户推送消息到窗口  ，推送内容:" + message);

        try {
            WebSocketServer sessionUser = userSession.get(BaseContext.getCurrentId());
            WebSocketServer sessionTarget = userSession.get(targetId);
            sessionUser.sendMessage(message);
            sessionTarget.sendMessage(message);
        } catch (IOException ignored) {
        }
    }


    //获取在线人数
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    //添加在线人数数量
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    //减少在线人数数量
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    //获取 websocket 服务器
    public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
        return webSocketSet;
    }
}